﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Net;

namespace Algobox.JuicyLib.Net.FTP
{
    public class JuicyFTP
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="inFtpUser">FTP Username</param>
        /// <param name="inFtpPass">FTP Password</param>
        /// <param name="inFtpURI">FTP and directory from which to retrieve files</param>
        /// <param name="mode">Unix or Windows mode</param>
        /// <param name="command">Passive or Aggressive</param>
        /// <exception cref="System.UriFormatException" />
        public JuicyFTP(string inFtpUser, string inFtpPass, string inFtpURI, FTPMode mode, FTPCommand command)
            : this(inFtpUser, inFtpPass, inFtpURI, String.Empty, new List<string>(), mode, command)
        { }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="inFtpUser">FTP Username</param>
        /// <param name="inFtpPass">FTP Password</param>
        /// <param name="inFtpURI">FTP and directory from which to retrieve files</param>
        /// <param name="inFtpBackupURI">Directory to backup file to on the FTP server</param>
        /// <param name="mode">Unix or Windows mode</param>
        /// <param name="command">Passive or Aggressive</param>
        /// <exception cref="System.UriFormatException" />
        public JuicyFTP(string inFtpUser, string inFtpPass, string inFtpURI, string inFtpBackupURI, FTPMode mode, FTPCommand command)
            : this(inFtpUser, inFtpPass, inFtpURI, inFtpBackupURI, new List<string>(), mode, command)
        { }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="inFtpUser">FTP Username</param>
        /// <param name="inFtpPass">FTP Password</param>
        /// <param name="inFtpURI">FTP and directory from which to retrieve files</param>
        /// <param name="inFtpBackupURI">Directory to backup file to on the FTP server</param>
        /// <param name="ignoreDirs">List of directories to ignore on teh FTP</param>
        /// <param name="mode">Unix or Windows mode</param>
        /// <param name="command">Passive or Aggressive</param>
        /// <exception cref="System.UriFormatException" />
        public JuicyFTP(string inFtpUser, string inFtpPass, string inFtpURI, string inFtpBackupURI, List<string> ignoreDirs, FTPMode mode, FTPCommand command)
        {
            FTP_PASS = inFtpPass;
            FTP_USER = inFtpUser;

            inFtpURI = inFtpURI.Trim();

            // check for malformed URI
            if (inFtpURI[inFtpURI.Length - 1] != '/')
                FTP_URI = new Uri(inFtpURI + '/');
            else
                FTP_URI = new Uri(inFtpURI);

            FTP_BACKUP_DIR = inFtpBackupURI;
            FTP_IGNORE_DIRS = ignoreDirs;

            _mode = mode;
            _command = command;
        }

        readonly string FTP_USER;
        readonly string FTP_PASS;
        readonly Uri FTP_URI;
        readonly string FTP_BACKUP_DIR;
        readonly List<string> FTP_IGNORE_DIRS;

        const string IS_DIR_WIN = "<DIR>";
        const int IX_WIN_DIR = 2;
        const int IX_WIN_NAME = 3;

        const char IS_DIR_NIX = 'd';
        const char IS_FILE_NIX = '-';
        const int IX_NIX_NAME = 8;
        const int IX_NIX_DIRFILE = 0;
        const int IX_NIX_SIZE = 4;
        const int IX_NIX_MONTH = 5;
        const int IX_NIX_DAY = 6;
        const int IX_NIX_TIME = 7;

        readonly FTPMode _mode;
        readonly FTPCommand _command;

        public enum FTPMode
        {
            Windows,
            Unix
        }

        public enum FTPCommand
        {
            Passive,
            Active
        }

        public static bool IsFTPUri(String uriString)
        {
            Uri uri;
            try
            {
                uri = new Uri(uriString);
            }
            catch
            {
                return false;
            }
            if (uri.Scheme != Uri.UriSchemeFtp)
            {
                return false;
            }
            return true;
        }

        /// <summary>
        /// Creates the FTP request for the base URI
        /// </summary>
        /// <returns></returns>
        private FtpWebRequest CreateRequest()
        {
            return CreateRequest(string.Empty);
        }

        /// <summary>
        /// Creates the FTP request for a specific file or directory
        /// </summary>
        /// <param name="name">File or Directory name</param>
        /// <returns></returns>
        private FtpWebRequest CreateRequest(string name)
        {
            // remove / from name
            if (name == "/")
                name = String.Empty;
            else if (name.Length > 1 && name[0] == '/')
                name = name.Substring(1);

            FtpWebRequest request = (FtpWebRequest)WebRequest.Create(FTP_URI.AbsoluteUri + name);
            request.Credentials = new NetworkCredential(FTP_USER, FTP_PASS);
            request.UsePassive = _command == FTPCommand.Passive;
            request.UseBinary = true;
            return request;
        }
    
        
        private FtpWebRequest CreateRequest(Uri uriLocation)
        {
            FtpWebRequest request = (FtpWebRequest)WebRequest.Create(uriLocation);
            request.UseBinary = true;
            request.Credentials = new NetworkCredential(FTP_USER, FTP_PASS);
            request.UsePassive = _command == FTPCommand.Passive;
            request.UseBinary = true;
            return request;
        }



        private byte[] DownloadData(string fileUri)
        {
            WebClient webRequest = new WebClient();

            webRequest.Credentials = new NetworkCredential(FTP_USER, FTP_PASS);

            byte[] newFileData = null;

            try
            {
                newFileData = webRequest.DownloadData(fileUri);
            }
            catch (WebException e)
            {
                Console.WriteLine(e.ToString());
            }

            return newFileData;
        }


        private bool UploadData(string fileUri, byte[] data)
        {
            WebClient webRequest = new WebClient();

            webRequest.Credentials = new NetworkCredential(FTP_USER, FTP_PASS);

            try
            {
                webRequest.UploadData(fileUri, data);
            }
            catch (WebException e)
            {
                Console.WriteLine(e.ToString());
                return false;
            }

            return true;
        }



        //
        // UNIX FTP server
        //
        // drwx------ 1 mailbox group           1024 Jul 31 11:08 archives
        // -rw------- 1 message group           1097 Jul 31 04:40 confirm.txt.1240.asc.09.07.31_04.40

        public bool TryGetFileList(out List<string> fileList)
        {
            fileList = new List<string>();

            StreamReader reader = null;

            string strCurLine;
            string[] arrFileProperties;

            FtpWebRequest request = CreateRequest();

            request.Method = WebRequestMethods.Ftp.ListDirectoryDetails;

            try
            {
                FtpWebResponse listResponse = (FtpWebResponse)request.GetResponse();
                reader = new StreamReader(listResponse.GetResponseStream());
                strCurLine = reader.ReadLine();

                if (_mode == FTPMode.Windows)
                {                    
                    while (strCurLine != null)
                    {
                        arrFileProperties = strCurLine.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);

                        if (arrFileProperties[IX_WIN_DIR] != IS_DIR_WIN)
                        {
                            fileList.Add(arrFileProperties[IX_WIN_NAME]);
                        }
                        strCurLine = reader.ReadLine();
                    }
                }
                // else unix mode
                else
                {
                    while (strCurLine != null)
                    {
                        if (strCurLine[0] == IS_FILE_NIX)
                        {
                            arrFileProperties = strCurLine.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                            fileList.Add(arrFileProperties[IX_NIX_NAME]);                            
                        }
                        strCurLine = reader.ReadLine();
                    }
                }
            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.WriteLine(e.ToString());
                System.Diagnostics.Trace.WriteLine("FTP FILE LISTING FAILED");
                Console.WriteLine("FTP FILE LISTING FAILED");
                return false;
            }


            return true;
        }
        


        public bool TryGetFileListRecursive(string directory, out List<string> fileList)
        {
            fileList = new List<string>();
            string strCurLine;
            string item;
            string[] fileDeets;

            List<string> directories = new List<string>();

            try
            {
                FtpWebRequest request = CreateRequest(directory);
                request.Method = WebRequestMethods.Ftp.ListDirectoryDetails;

                FtpWebResponse response = (FtpWebResponse)request.GetResponse();
                using (StreamReader reader = new StreamReader(response.GetResponseStream()))
                {
                    strCurLine = reader.ReadLine();

                    while (strCurLine != null)
                    {

                        if (_mode == FTPMode.Windows)
                        {
                            fileDeets = strCurLine.Split(new char[] { ' ' }, 4, StringSplitOptions.RemoveEmptyEntries);

                            // directory
                            if (fileDeets[IX_WIN_DIR] == IS_DIR_WIN)
                            {
                                item = fileDeets[IX_WIN_NAME];

                                if (!FTP_IGNORE_DIRS.Contains(item))
                                    directories.Add(item);
                            }
                            // files
                            else
                            {
                                if (directory == String.Empty)
                                    item = fileDeets[IX_WIN_NAME];
                                else
                                    item = directory + "/" + fileDeets[IX_WIN_NAME];

                                fileList.Add(item);
                            }
                        }
                        // else nix mode
                        else
                        {
                            // file
                            if (strCurLine[0] == IS_FILE_NIX)
                            {
                                fileDeets = strCurLine.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                                
                                if (directory == String.Empty)
                                    item = fileDeets[IX_NIX_NAME];
                                else
                                    item = directory + "/" + fileDeets[IX_NIX_NAME];

                                fileList.Add(item);
                            }
                            // directory
                            else if (strCurLine[0] == IS_DIR_NIX)
                            {
                                fileDeets = strCurLine.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);

                                item = fileDeets[IX_NIX_NAME];

                                if(!FTP_IGNORE_DIRS.Contains(item))
                                    directories.Add(item);
                            }
                        }
                        strCurLine = reader.ReadLine();
                    }

                    response.Close();
                    response = null;
                    request = null;
                }

                // recurse into directories
                foreach (string dir in directories)
                {
                    List<string> innerFileList;

                    string subDirectory;

                    if (directory == String.Empty)
                        subDirectory = dir;
                    else
                        subDirectory = directory + "/" + dir;

                    if (FTP_URI.AbsoluteUri + subDirectory + "/" != FTP_BACKUP_DIR)
                    {
                        if (TryGetFileListRecursive(subDirectory, out innerFileList))
                        {
                            if (innerFileList.Count > 0)
                                fileList.AddRange(innerFileList);
                        }
                    }
                }

            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.WriteLine(e.ToString());
                System.Diagnostics.Trace.WriteLine("FTP FILE LISTING FAILED");
                Console.WriteLine("FTP FILE LISTING FAILED");
                return false;
            }


            return true;
        }

        public bool TryGetFileListRecursive(string directory, out List<FileDetails> fileList)
        {
            fileList = new List<FileDetails>();
            
            string strCurLine;
            string item;
            string[] fileDeets;
            string fileDateString;
            int fileSize;

            List<string> directories = new List<string>();

            try
            {
                FtpWebRequest request = CreateRequest(directory);
                request.Method = WebRequestMethods.Ftp.ListDirectoryDetails;

                FtpWebResponse response = (FtpWebResponse)request.GetResponse();
                using (StreamReader reader = new StreamReader(response.GetResponseStream()))
                {
                    strCurLine = reader.ReadLine();

                    while (strCurLine != null)
                    {
                        if (_mode == FTPMode.Windows)
                        {
                            fileDeets = strCurLine.Split(new char[] { ' ' }, 4, StringSplitOptions.RemoveEmptyEntries);

                            // directory
                            if (fileDeets[IX_WIN_DIR] == IS_DIR_WIN)
                            {
                                item = fileDeets[IX_WIN_NAME];

                                if (!FTP_IGNORE_DIRS.Contains(item))
                                    directories.Add(item);
                            }
                            // files
                            else
                            {
                                if (directory == String.Empty)
                                    item = fileDeets[IX_NIX_NAME];
                                else
                                    item = directory + "/" + fileDeets[IX_NIX_NAME];

                                fileList.Add(new FileDetails() { FileName = fileDeets[IX_WIN_NAME], FilePath = item });
                            }
                        }
                        // else nix mode
                        else
                        {
                            // file
                            if (strCurLine[0] == IS_FILE_NIX)
                            {
                                fileDeets = strCurLine.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);

                                if (directory == String.Empty)
                                    item = fileDeets[IX_NIX_NAME];
                                else
                                    item = directory + "/" + fileDeets[IX_NIX_NAME];

                                fileSize = Int32.Parse(fileDeets[IX_NIX_SIZE]);
                                fileDateString = String.Format("{0} {1} {2}", fileDeets[IX_NIX_MONTH], fileDeets[IX_NIX_DAY], fileDeets[IX_NIX_TIME]);

                                fileList.Add(new FileDetails() { FileName = fileDeets[IX_NIX_NAME], FilePath = item, FileSize = fileSize, FileDateString = fileDateString });
                            }
                            // directory
                            else if (strCurLine[0] == IS_DIR_NIX)
                            {
                                fileDeets = strCurLine.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);

                                item = fileDeets[IX_NIX_NAME];

                                if (!FTP_IGNORE_DIRS.Contains(item))
                                    directories.Add(item);
                            }
                        }
                        strCurLine = reader.ReadLine();
                    }

                    response.Close();
                    response = null;
                    request = null;
                }

                // recurse into directories
                foreach (string dir in directories)
                {
                    List<FileDetails> innerFileList;

                    string subDirectory;

                    if (directory == String.Empty)
                        subDirectory = dir;
                    else
                        subDirectory = directory + "/" + dir;

                    if (FTP_URI.AbsoluteUri + subDirectory + "/" != FTP_BACKUP_DIR)
                    {
                        if (TryGetFileListRecursive(subDirectory, out innerFileList))
                        {
                            if (innerFileList.Count > 0)
                                fileList.AddRange(innerFileList);
                        }
                    }
                }

            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.WriteLine(e.ToString());
                System.Diagnostics.Trace.WriteLine("FTP FILE LISTING FAILED");
                Console.WriteLine("FTP FILE LISTING FAILED");
                return false;
            }


            return true;
        }


        public bool GetFileAsStream(string fileName, out Stream reader)
        {
            FtpWebRequest request = CreateRequest(fileName);

            try
            {
                FtpWebResponse getResponse = (FtpWebResponse)request.GetResponse();
                reader = getResponse.GetResponseStream();
            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.WriteLine(e.ToString());
                System.Diagnostics.Trace.WriteLine("FTP FILE LISTING FAILED");

                reader = null;
                return false;
            }

            return true;
        }


        public bool GetFileAsStreamReader(string fileName, out StreamReader reader)
        {
            System.Diagnostics.Trace.WriteLine("FTP FILE READER STARTING");

            reader = null;

            FtpWebRequest request = CreateRequest(fileName);
            
            try
            {
                FtpWebResponse getResponse = (FtpWebResponse)request.GetResponse();
                reader = new StreamReader(getResponse.GetResponseStream());
            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.WriteLine(e.ToString());
                System.Diagnostics.Trace.WriteLine("FTP FILE LISTING FAILED");

                reader = null;
                return false;
            }

            return true;
        }


        public bool GetFileAsString(string fileName, out string fileData)
        {
            fileData = String.Empty;
            StreamReader reader;

            if (GetFileAsStreamReader(fileName, out reader))
            {
                try
                {
                    fileData = reader.ReadToEnd();
                    return true;
                }
                catch
                {
                    return false;
                }
            }
            return false;
        }


        public bool GetFileAsString(string fileName, out string fileData, out Encoding encoding)
        {
            fileData = String.Empty;
            encoding = Encoding.Default;
            StreamReader reader;

            if (GetFileAsStreamReader(fileName, out reader))
            {
                try
                {
                    fileData = reader.ReadToEnd();
                    encoding = reader.CurrentEncoding;
                    return true;
                }
                catch
                {
                    return false;
                }
            }
            return false;
        }


        public bool TryBackupFile(string fileName)
        {
            if (FTP_BACKUP_DIR == String.Empty)
            {
                System.Diagnostics.Trace.WriteLine("FTP FILE BACKUP FAILED - NO BACKUP URI");
                Console.WriteLine("FTP FILE BACKUP FAILED - NO BACKUP URI");
                return false;
            }
            else
            {
                string message;
                return TryBackupFile(fileName, FTP_BACKUP_DIR, out message);
            }
        }

        public bool TryBackupFile(string fileName, string backupDir)
        {
            string message;
            return TryBackupFile(fileName, FTP_BACKUP_DIR, out message);
        }

        public bool TryBackupFile(string fileName, string backupDir, out string message)
        {
            bool bBackupSuccess = false;

            if (CreateDirectoryRecursive(backupDir))
            {
                Uri backupUri = new Uri(backupDir);

                // load file request
                FtpWebRequest request = CreateRequest(fileName);

                fileName = fileName.Substring(fileName.LastIndexOf('/') + 1);

                try
                {
                    DeleteFile(backupUri.LocalPath + fileName);

                    System.Diagnostics.Debug.WriteLine("FTP Backing up " + backupUri.LocalPath + fileName);

                    request.Method = WebRequestMethods.Ftp.Rename;

                    request.RenameTo = backupUri.LocalPath + "/" + fileName;

                    FtpWebResponse response = (FtpWebResponse)request.GetResponse();

                    Stream renameStream = response.GetResponseStream();

                    renameStream.Close();

                    response.Close();

                    bBackupSuccess = true;

                    message = "FTP file backup successful from " + backupUri.LocalPath + fileName + " to " + backupDir + fileName;

                    System.Diagnostics.Trace.WriteLine(message);
                }
                catch (Exception e)
                {
                    message = "FTP file backup failed from " + backupUri.LocalPath + fileName + " to " + backupDir + fileName;
                    System.Diagnostics.Debug.WriteLine(e.ToString());
                    System.Diagnostics.Debug.WriteLine(message);
                }
            }
            else
            {
                message = "FTP file backup failed to recursivly create directory " + backupDir + fileName;
            }
            
            return bBackupSuccess;
        }


        public bool TryBackupStagedFile(string fileName, string backupDir, Uri stagedFile)
        {
            Uri backupUri = new Uri(FTP_URI.AbsoluteUri + backupDir + "/" + fileName);

            // check directory to backup to is in place and writable
            if (CreateDirectoryRecursive(FTP_URI.AbsoluteUri + backupDir + "/" + Path.GetDirectoryName(fileName)))
            {
                // load file request
                FtpWebRequest request = CreateRequest(stagedFile);
                
                try
                {
                    DeleteFile(backupUri);

                    System.Diagnostics.Debug.WriteLine("FTP Backing up " + fileName);

                    request.Method = WebRequestMethods.Ftp.Rename;

                    request.RenameTo = backupUri.LocalPath;

                    FtpWebResponse response = (FtpWebResponse)request.GetResponse();

                    Stream renameStream = response.GetResponseStream();

                    renameStream.Close();

                    response.Close();

                    return true;
                }
                catch (Exception e)
                {
                    Console.WriteLine("Failed to backup file on FTP");
                    System.Diagnostics.Debug.WriteLine(e.ToString());
                }
                // failed to move the staged file so delete from staging area
                try
                {
                    DeleteFile(stagedFile);
                }
                catch (Exception e)
                {
                    Console.WriteLine("Failed to delete file from staging area");
                    System.Diagnostics.Debug.WriteLine(e.ToString());
                }
            }
            return false;
        }


        public bool TryStageFile(string fileName, string stageDir, out Uri stagedUri, out Stream reader)
        {
            stagedUri = new Uri(FTP_URI.AbsoluteUri + stageDir + "/");

            try
            {
                // load file request
                FtpWebRequest request = CreateRequest(fileName);

                // strip off directory from filename
                fileName = fileName.Substring(fileName.LastIndexOf('/') + 1);                
                System.Diagnostics.Debug.WriteLine("Staging " + stagedUri.LocalPath + fileName);

                request.Method = WebRequestMethods.Ftp.Rename;
                request.RenameTo = stagedUri.LocalPath + fileName;

                using (FtpWebResponse response = (FtpWebResponse)request.GetResponse())
                {
                    using (Stream renameStream = response.GetResponseStream())
                    { }
                }
                request = null;
                
                // if no exception caught then stage was successful

                // create stream from staged file
                request = (FtpWebRequest)WebRequest.Create(stagedUri.AbsoluteUri + fileName);
                request.Credentials = new NetworkCredential(FTP_USER, FTP_PASS);
                request.UsePassive = _command == FTPCommand.Passive;
                request.UseBinary = true;

                try
                {
                    FtpWebResponse response = (FtpWebResponse)request.GetResponse();                    
                    reader = response.GetResponseStream();
                    stagedUri = request.RequestUri;                    
                    return true;
                }
                catch (Exception e)
                {
                    System.Diagnostics.Debug.WriteLine("Failed to stage: " + e.ToString());
                }                
            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.WriteLine("Failed to stage: " + e.ToString());
            }

            reader = null;

            return false;
        }


        public bool DeleteFile(string fileName)
        {
            System.Diagnostics.Trace.WriteLine("FTP FILE DELETE STARTING");

            try
            {
                FtpWebRequest request = CreateRequest(fileName);
                
                FtpWebResponse response = (FtpWebResponse)request.GetResponse();
            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.WriteLine(e.ToString());
                System.Diagnostics.Trace.WriteLine("FTP FILE DELETE FAILED");
                return false;
            }

            return true;
        }


        public bool DeleteFile(Uri location)
        {
            System.Diagnostics.Trace.WriteLine("FTP FILE DELETE STARTING");

            try
            {
                FtpWebRequest request = (FtpWebRequest)WebRequest.Create(location);
                request.Credentials = new NetworkCredential(FTP_USER, FTP_PASS);
                request.UseBinary = true;

                request.Method = WebRequestMethods.Ftp.DeleteFile;
                request.UsePassive = false;

                FtpWebResponse response = (FtpWebResponse)request.GetResponse();
            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.WriteLine(e.ToString());
                System.Diagnostics.Trace.WriteLine("FTP FILE DELETE FAILED");
                return false;
            }

            return true;
        }


        List<string> _cacheExistingDirectories;

        public bool CreateDirectoryRecursive(string remoteDirPath)
        {
            return CreateDirectoryRecursive(new Uri(remoteDirPath));
        }

        public bool CreateDirectoryRecursive(Uri remoteUri)
        {
            FtpWebRequest request;

            if (_cacheExistingDirectories == null)
            {
                _cacheExistingDirectories = new List<string>();
                try
                {
                    request = (FtpWebRequest)WebRequest.Create(FTP_URI + FTP_BACKUP_DIR + "/");
                    request.Credentials = new NetworkCredential(FTP_USER, FTP_PASS);
                    request.Method = WebRequestMethods.Ftp.ListDirectory;
                    try
                    {
                        using (StreamReader stream = new StreamReader(((FtpWebResponse)request.GetResponse()).GetResponseStream()))
                        {
                            var container = stream.ReadToEnd().Split(new char[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
                            foreach (string item in container)
                            {
                                _cacheExistingDirectories.Add(request.RequestUri.AbsoluteUri + item);
                            }
                        }
                    }
                    catch
                    {
                        System.Diagnostics.Debug.WriteLine("Directory not found for " + remoteUri.AbsoluteUri);
                        Console.WriteLine("Directory not found for " + remoteUri.AbsoluteUri);
                    }
                }
                catch
                { }
            }

            if (_cacheExistingDirectories.Contains(remoteUri.AbsoluteUri))
                return true;

            try
            {
                string dir = String.Empty;
                foreach (string dirPart in remoteUri.Segments)
                {
                    if (FTP_URI.AbsoluteUri.Contains(dirPart))
                        continue;

                    dir += dirPart;

                    //request = (FtpWebRequest)WebRequest.Create(FTP_URI + dir);
                    //request.Credentials = new NetworkCredential(FTP_USER, FTP_PASS);
                    //request.Method = WebRequestMethods.Ftp.ListDirectory;
                    try
                    {
                        request = (FtpWebRequest)WebRequest.Create(FTP_URI + dir);
                        request.Credentials = new NetworkCredential(FTP_USER, FTP_PASS);
                        request.Method = WebRequestMethods.Ftp.MakeDirectory;

                        using (var resp = (FtpWebResponse)request.GetResponse())
                        {
                            Console.WriteLine(resp.StatusCode + " " + FTP_URI + dir);
                        }
                    }
                    catch
                    { }
                }
                _cacheExistingDirectories.Add(remoteUri.AbsoluteUri);
                return true;
            }
            catch
            {
                System.Diagnostics.Debug.WriteLine("Failed to create (or check) directories for " + remoteUri.AbsoluteUri);
                Console.WriteLine("Failed to create (or check) directories for " + remoteUri.AbsoluteUri);
            }
            return false;
        }

    }
}
